// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
//
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.ui.prefs.connectivity.ui;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Properties;

import org.dengues.commons.IDenguesSharedImage;
import org.dengues.commons.connectivity.IConnectivitySettingsConstants;
import org.dengues.commons.utils.DriverUtil;
import org.dengues.commons.utils.ImageUtil;
import org.dengues.core.i18n.Messages;
import org.dengues.ui.prefs.connectivity.ConnectivityManager;
import org.dengues.ui.prefs.connectivity.XMLFileManager;
import org.dengues.ui.prefs.connectivity.models.ConnectivityCategory;
import org.dengues.ui.prefs.connectivity.models.ConnectivityProperty;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.PageBook;
import org.eclipse.ui.views.properties.PropertySheetPage;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 1 2006-09-29 17:06:40Z qiang.zhang $
 * 
 */
public class ConnectivityDialog extends TitleAreaDialog {

    private Text connNameText;

    private final ArrayList<String> driverClasses = new ArrayList<String>();

    private String connName;

    private Text connTypeText;

    private List list;

    private Button addJar;

    private Button editJar;

    private Button removeJar;

    private Button clearAll;

    private String connId;

    private PageBook book;

    private ConnectivityProperty property;

    private ConnectivityCategory descriptor;

    private ConnectivityPropertySourceProvider sourceProvider;

    private String jarList;

    private Properties properties;

    private Button okButton;

    private java.util.List<String> existNames;

    /**
     * Qiang.Zhang.Adolf@gmail.com ConnectivityDialog constructor comment.
     * 
     * @param parentShell
     */
    private ConnectivityDialog(Shell parentShell) {
        super(parentShell);
        setShellStyle(getShellStyle() | SWT.RESIZE | SWT.DIALOG_TRIM);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com ConnectivityDialog constructor comment.
     * 
     * @param shell
     * @param descriptor
     */
    public ConnectivityDialog(Shell shell, ConnectivityCategory descriptor, java.util.List<String> existNames) {
        this(shell);
        this.existNames = existNames;
        if (descriptor instanceof ConnectivityProperty) {
            this.descriptor = descriptor.getParent();
            property = (ConnectivityProperty) descriptor;
            connId = this.descriptor.getId();
            connName = this.property.getName();
            jarList = this.property.getBaseProperties().getProperty(IConnectivitySettingsConstants.PROP_DEFN_JARLIST);
        } else {
            this.descriptor = descriptor;
            property = null;
            connId = this.descriptor.getId();
            connName = connId;
            jarList = ""; //$NON-NLS-1$
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        GridLayout gridLayout = new GridLayout();
        Composite area = (Composite) super.createDialogArea(parent);
        gridLayout.marginBottom = 0;
        gridLayout.marginHeight = 0;
        gridLayout.marginLeft = 0;
        gridLayout.marginRight = 0;
        gridLayout.marginTop = 0;
        gridLayout.marginWidth = 0;
        area.setLayout(gridLayout);

        Composite contents = new Composite(area, SWT.NONE);
        gridLayout = new GridLayout();
        gridLayout.marginBottom = 0;
        gridLayout.marginHeight = 0;
        gridLayout.marginLeft = 0;
        gridLayout.marginRight = 0;
        gridLayout.marginTop = 0;
        gridLayout.marginWidth = 0;
        contents.setLayout(gridLayout);
        contents.setLayoutData(new GridData(GridData.FILL_BOTH));

        final Composite composite = new Composite(contents, SWT.NONE);
        composite.setLayoutData(new GridData(GridData.FILL_BOTH));
        gridLayout.marginBottom = 0;
        gridLayout.marginHeight = 0;
        gridLayout.marginLeft = 0;
        gridLayout.marginRight = 0;
        gridLayout.marginTop = 0;
        gridLayout.marginWidth = 0;
        gridLayout = new GridLayout();
        composite.setLayout(gridLayout);
        createNameAndType(composite);
        if (descriptor.getType().getNestedDriver() != null) {
            jarList = descriptor.getType().getNestedDriver();
        } else {
            createJarsList(composite);
        }
        createProperties(composite);
        setTitleImage(ImageUtil.getImage(IDenguesSharedImage.PREFS_CONNSET64));
        setTitle(Messages.getString("ConnectivityDialog.title.msg")); //$NON-NLS-1$
        updateForConnectivityProperty();
        if (property == null) {
            validateName();
        }
        updateStatus();
        return area;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "updateStatus".
     */
    private void updateStatus() {
        if (property != null) {
            property.validate();
            if (!property.isValid()) {
                setErrorMessage(property.getStatusMessage());
            } else {
                setErrorMessage(null);
                setMessage(property.getStatusMessage());
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
     */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        // create OK and Cancel buttons by default
        okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
        okButton.setEnabled(!existNames.contains(connName));
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "updateForConnectivityProperty".
     */
    private void updateForConnectivityProperty() {
        if (property != null) {
            validateName();
            connName = property.getName();
            String jarList = property.getBaseProperties().getProperty(IConnectivitySettingsConstants.PROP_DEFN_JARLIST);
            this.jarList = jarList;
            if (list != null) {
                String[] jarListArray = XMLFileManager.parseString(jarList);
                list.removeAll();
                for (int i = 0; i < jarListArray.length; i++) {
                    list.add(jarListArray[i]);
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
     */
    @Override
    protected void configureShell(Shell newShell) {
        super.configureShell(newShell);
        newShell.setSize(540, 510);
        newShell.setText(Messages.getString("ConnectivityDialog.title")); //$NON-NLS-1$
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createProperties".
     * 
     * @param composite
     */
    private void createProperties(final Composite composite) {
        final Composite composite_3 = new Composite(composite, SWT.NONE);
        GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
        gridData.horizontalSpan = 2;
        composite_3.setLayoutData(gridData);
        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 2;
        gridLayout.marginBottom = 0;
        gridLayout.marginHeight = 0;
        gridLayout.marginLeft = 0;
        gridLayout.marginRight = 0;
        gridLayout.marginTop = 0;
        gridLayout.marginWidth = 0;
        composite_3.setLayout(gridLayout);

        final Label label = new Label(composite_3, SWT.NONE);
        label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        label.setText(Messages.getString("ConnectivityDialog.properties")); //$NON-NLS-1$
        final Button button = new Button(composite_3, SWT.NONE | SWT.RIGHT);
        gridData = new GridData(GridData.END);
        button.setLayoutData(gridData);
        button.setText(Messages.getString("ConnectivityDialog.testConn")); //$NON-NLS-1$
        button.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                testConnection();
            }
        });
        final Composite composite_2 = new Composite(composite, SWT.NONE);
        gridData = new GridData(GridData.FILL_BOTH);
        gridData.horizontalIndent = 0;
        gridData.horizontalSpan = 2;
        composite_2.setLayoutData(gridData);
        gridLayout = new GridLayout();
        gridLayout.numColumns = 2;
        gridLayout.marginBottom = 0;
        gridLayout.marginHeight = 0;
        gridLayout.marginLeft = 0;
        gridLayout.marginRight = 0;
        gridLayout.marginTop = 0;
        gridLayout.marginWidth = 0;
        composite_2.setLayout(gridLayout);

        book = new PageBook(composite_2, SWT.NONE);
        book.setLayoutData(new GridData(GridData.FILL_BOTH));
        PropertySheetPage page = new PropertySheetPage();
        page.createControl(book);
        sourceProvider = new ConnectivityPropertySourceProvider();
        page.setPropertySourceProvider(sourceProvider);
        book.showPage(page.getControl());
        if (property != null) {
            page.selectionChanged(null, new StructuredSelection(property));
        } else {
            page.selectionChanged(null, new StructuredSelection(descriptor));
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "testConnection".
     */
    protected void testConnection() {
        ConnectivityPropertySource connectivityPropertySource = sourceProvider.getConnectivityPropertySource();
        properties = connectivityPropertySource.getProperties();
        properties.setProperty(IConnectivitySettingsConstants.PROP_DEFN_JARLIST, jarList);
        ConnectivityManager.getInstance().testConnection(getShell(), properties, descriptor.getType().getNestedDriver() != null);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createJarsList".
     * 
     * @param composite
     */
    private void createJarsList(final Composite composite) {
        final Composite composite_3 = new Composite(composite, SWT.NONE);
        GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
        gridData.horizontalSpan = 2;
        composite_3.setLayoutData(gridData);
        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 2;
        gridLayout.marginBottom = 0;
        gridLayout.marginHeight = 0;
        gridLayout.marginLeft = 0;
        gridLayout.marginRight = 0;
        gridLayout.marginTop = 0;
        gridLayout.marginWidth = 0;
        composite_3.setLayout(gridLayout);

        final Label label = new Label(composite_3, SWT.NONE);
        label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        label.setText(Messages.getString("ConnectivityDialog.jarlist")); //$NON-NLS-1$
        final Button button = new Button(composite_3, SWT.NONE | SWT.RIGHT);
        gridData = new GridData();
        button.setLayoutData(gridData);
        button.setText(Messages.getString("ConnectivityDialog.testDriver")); //$NON-NLS-1$
        button.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                testDrivers();
            }
        });

        final Composite composite_1 = new Composite(composite, SWT.NONE);
        gridData = new GridData(GridData.FILL_HORIZONTAL);
        gridData.horizontalIndent = 0;
        gridData.horizontalSpan = 2;
        composite_1.setLayoutData(gridData);
        final GridLayout gridLayout_1 = new GridLayout();
        gridLayout_1.numColumns = 3;
        composite_1.setLayout(gridLayout_1);
        list = new List(composite_1, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        final GridData gridData_1 = new GridData(GridData.FILL_BOTH);
        gridData_1.verticalSpan = 4;
        gridData_1.horizontalSpan = 2;
        list.setLayoutData(gridData_1);
        list.addSelectionListener(new SelectionListener() {

            public void widgetSelected(SelectionEvent e) {
                if (list.getSelectionCount() > 0) {
                    editJar.setEnabled(true);
                    removeJar.setEnabled(true);
                }
            }

            public void widgetDefaultSelected(SelectionEvent e) {
                widgetSelected(e);
            }
        });
        addJar = new Button(composite_1, SWT.NONE);
        addJar.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                handleLocationBrowseButtonPressed(addJar.getText(), null);
                updateJarList();
            }
        });
        addJar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
        addJar.setText(Messages.getString("ConnectivityDialog.addJar")); //$NON-NLS-1$
        editJar = new Button(composite_1, SWT.NONE);
        editJar.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                handleLocationBrowseButtonPressed(editJar.getText(), list.getItem(list.getSelectionIndex()));
                updateJarList();
            }
        });
        editJar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
        editJar.setText(Messages.getString("ConnectivityDialog.editJar")); //$NON-NLS-1$
        editJar.setEnabled(false);
        removeJar = new Button(composite_1, SWT.NONE);
        removeJar.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                int selectionIndex = list.getSelectionIndex();
                if (list.getItemCount() > selectionIndex) {
                    list.remove(selectionIndex);
                    updateJarList();
                }
            }
        });
        removeJar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
        removeJar.setText(Messages.getString("ConnectivityDialog.removeJar")); //$NON-NLS-1$
        removeJar.setEnabled(false);

        clearAll = new Button(composite_1, SWT.NONE);
        clearAll.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_BEGINNING));
        clearAll.setText(Messages.getString("ConnectivityDialog.clearAll")); //$NON-NLS-1$
        clearAll.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                list.removeAll();
                updateJarList();
            }
        });
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "updateJarList".
     */
    protected void updateJarList() {
        if (list == null) {
            return;
        }
        jarList = createList(list.getItems());
        if (jarList.length() == 0) {
            setErrorMessage(Messages.getString("ConnectivityProperty.emptyJars")); //$NON-NLS-1$
        } else {
            StringBuilder builder = new StringBuilder(Messages.getString("ConnectivityProperty.unableLocation")); //$NON-NLS-1$
            boolean b = true;
            for (String string : list.getItems()) {
                File file = new File(string);
                if (!file.exists()) {
                    b = false;
                    builder.append(string);
                }
            }
            if (b) {
                setErrorMessage(null);
                setMessage(Messages.getString("ConnectivityProperty.okStatus")); //$NON-NLS-1$
            } else {
                setErrorMessage(builder.toString());
            }
        }
    }

    private String createList(String[] items) {
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < items.length; i++) {
            if (items[i] != null) {
                buffer.append(items[i]);
                if (i + 1 < items.length)
                    buffer.append(IConnectivitySettingsConstants.PATH_DELIMITER);
            }
        }
        return buffer.toString();
    }

    /*
     * Open an appropriate directory browser
     */
    private void handleLocationBrowseButtonPressed(String title, String location) {
        FileDialog dialog = new FileDialog(getShell());
        dialog.setText(title);

        String dirName = location == null ? "" : location; //$NON-NLS-1$
        dialog.setFilterExtensions(new String[] { "*.jar", "*.zip", "*.dll" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        if (dirName.length() != 0) {
            File path = new File(dirName);
            if (path.exists())
                dialog.setFilterPath(new Path(dirName).toOSString());
        }

        String selectedDirectory = dialog.open();
        if (selectedDirectory != null) {
            if (dirName.length() != 0) {
                list.remove(dirName);
            }
            list.add(selectedDirectory);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createNameAndType".
     * 
     * @param composite
     */
    private void createNameAndType(final Composite composite) {
        Label label = new Label(composite, SWT.NONE);
        label.setText(Messages.getString("ConnectivityDialog.connName")); //$NON-NLS-1$
        connNameText = new Text(composite, SWT.BORDER);
        connNameText.setText(connName);
        connNameText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        connNameText.addModifyListener(new ModifyListener() {

            public void modifyText(ModifyEvent e) {
                connName = connNameText.getText();
                validateName();
            }
        });
        label = new Label(composite, SWT.NONE);
        label.setText(Messages.getString("ConnectivityDialog.connType")); //$NON-NLS-1$
        connTypeText = new Text(composite, SWT.BORDER);
        connTypeText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        connTypeText.setText(connId);
        connTypeText.setEnabled(false);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "validateName".
     */
    public void validateName() {
        boolean is = false;
        if (existNames != null && existNames.contains(connName)) {
            setErrorMessage(Messages.getString("ConnectivityDialog.existConn")); //$NON-NLS-1$
        } else {
            updateJarList();
            is = true;
        }
        if (okButton != null) {
            okButton.setEnabled(is);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.jface.dialogs.Dialog#okPressed()
     */
    @Override
    protected void okPressed() {
        if (property == null) {
            property = new ConnectivityProperty(descriptor, connName);
        }
        property.setName(connName);
        Properties props = new Properties();
        ConnectivityPropertySource connectivityPropertySource = sourceProvider.getConnectivityPropertySource();
        properties = connectivityPropertySource.getProperties();
        for (Enumeration enu = properties.propertyNames(); enu.hasMoreElements();) {
            String key = (String) enu.nextElement();
            String value = properties.getProperty(key);
            props.setProperty(key, value);
        }
        props.setProperty(IConnectivitySettingsConstants.PROP_DEFN_JARLIST, jarList);
        property.setBaseProperties(props);
        super.okPressed();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getNewDriverInstance".
     * 
     * @return
     */
    public ConnectivityProperty getNewInstance() {
        return property;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "testDrivers".
     */
    private void testDrivers() {
        for (String filepath : list.getItems()) {
            final File file = new File(filepath);
            ProgressMonitorDialog pmd = new ProgressMonitorDialog(getShell());
            pmd.setCancelable(true);
            try {
                pmd.run(true, false, new IRunnableWithProgress() {

                    public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
                        try {
                            final String[] driverClasses2 = DriverUtil.getDriverClassesFromJar(file, monitor);
                            driverClasses.addAll(Arrays.asList(driverClasses2));
                        } catch (Exception e1) {
                            e1.printStackTrace();
                        }
                    }
                });
            } catch (InvocationTargetException ex) {
                ex.printStackTrace();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        getShell().getDisplay().asyncExec(new Runnable() {

            public void run() {
                sourceProvider.getConnectivityPropertySource().setDriverClasses(driverClasses);
            }
        });
    }

}
